#include <iostream>
#include <memory>
using namespace std;

/* counter对象的目地就是用来申请一个块内存来存引用基数，
s是share_ptr的引用计数，w是weak_ptr的引用计数，当w为0时，
删除Counter对象。*/
class Counter
{
public:
    Counter():s(0), w(0) {};
public:
    int s;//shared_ptr的引用计数
    int w;//shared_ptr的引用计数
};

template <class T>
class WeakPtr; //为了用weak_ptr的lock()，来生成share_ptr用，需要拷贝构造用

/*SharePtr
share_ptr的给出的函数接口为：构造，拷贝构造，赋值，解引用，通过release来在引用计数为0的时候删除_ptr和cnt的内存。
*/
template <class T>
class SharePtr
{
public:
    SharePtr(T *p = 0) : _ptr(p)
    {
        cnt = new Counter();
        if (p)
            cnt->s = 1;
        cout << "in construct " << cnt->s << endl;
    }
    ~SharePtr()
    {
        release();
    }

    SharePtr(SharePtr<T> const &s)
    {
        cout << "in copy con" << endl;
        _ptr = s._ptr;
        (s.cnt)->s++;
        cout << "copy construct" << (s.cnt)->s << endl;
        cnt = s.cnt;
    }
    SharePtr(WeakPtr<T> const &w) //为了用weak_ptr的lock()，来生成share_ptr用，需要拷贝构造用
    {
        cout << "in w copy con " << endl;
        _ptr = w._ptr;
        (w.cnt)->s++;
        cout << "copy w  construct" << (w.cnt)->s << endl;
        cnt = w.cnt;
    }
    SharePtr<T> &operator=(SharePtr<T> &s)
    {
        if (this != &s)
        {
            release();
            (s.cnt)->s++;
            cout << "assign construct " << (s.cnt)->s << endl;
            cnt = s.cnt;
            _ptr = s._ptr;
        }
        return *this;
    }
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }
    friend class WeakPtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值

protected:
    void release()
    {
        cnt->s--;
        cout << "release " << cnt->s << endl;
        if (cnt->s < 1)
        {
            delete _ptr;
            if (cnt->w < 1)
            {
                delete cnt;
                cnt = NULL;
            }
        }
    }

private:
    T *_ptr;
    Counter *cnt;
};

//WeakPtr:weak_ptr一般通过share_ptr来构造，通过expired函数检查原始指针是否为空，lock来转化为share_ptr。
template <class T>
class WeakPtr
{
public://给出默认构造和拷贝构造，其中拷贝构造不能有从原始指针进行构造
    WeakPtr()
    {
        _ptr = 0;
        cnt = 0;
    }

    WeakPtr(sharePtr<T> &s) : _ptr(s._ptr), cnt(s.cnt)
    {
        cout << "w con s "<< endl;
        cnt++;
    }

    WeakPtr(WeakPtr<T> &s) : _ptr(s._ptr), cnt(s.cnt)
    {
        cnt->w++;
    }
    ~WeakPtr()
    {
        release();
    }

    WeakPtr<T> &operator=(WeakPtr<T> *w)
    {
        if(this != &w)
        {
            release();
            cnt->w.cnt;
            cnt->w++;
            _ptr = w._ptr;
        }
        return *this;
    }

    WeakPtr<T> &operator= (SharePtr<T> &s) //为了用weak_ptr的lock()，来生成share_ptr用，需要拷贝构造用
    {
        cout << "w = s" << endl;
        release();
        cnt = s.cnt;
        cnt->w++;
        _ptr = s._ptr;
        return *this;
    }
    SharePtr<T> lock()
    {
        return SharePtr<T> (*this);
    }
    
    bool expired()
    {
        if(cnt)
        {
            if(cnt->s > 0)
            {
                cout<<"empty"<<cnt->s<<endl;
                return false;
            }
        }
        return true;
    }
    friend class SharePtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值

protected:
    void release()
    {
        if (cnt)
        {
            cnt->w--;
            cout<<"weakPtr realease"<<cnt->w<<endl;
            if(cnt->w < 1 && cnt->s < 1)
            {
                delete _ptr;
                cnt = NULL;
            }
        }
    }

private:
    T *_ptr;
    Counter *cnt;
};

